/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package reversi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author T
 */
public class minimax {
    int[][] tab = new int[8][8];
    int[][] tableroPesos = new int[8][8];
   // nodo nodoActual;
    static int VACIO = 0;
    static int BLANCO = 1;
    static int NEGRO = 2;
    static int COMPUTADORA = 2;
    static int PERSONA = 1;
    boolean finjuego = false;
   // nodo raiz;
    boolean pasaTurno = false;
     int PosXin = -1;
    int PosYin = -1;
    int profundidad=16;
    int sinjugadas=0;
    int sintiros=0;
    
    public minimax(){
        for (int i=0;i<8;i++){
            for(int j=0; j<8; j++){
                tab[i][j] = 0;
            }            
        }
        tab[3][3]=BLANCO; //blanco
        tab[3][4]=NEGRO;  //negro
        tab[4][3]=NEGRO;
        tab[4][4]=BLANCO;
        
    //    tab[5][7]=NEGRO;
    //    tab[6][7]=BLANCO;
    //    tab[7][7]=NEGRO;
        /*****ADICIONALES DE PRUEBA***
        tab[0][1]=NEGRO;
        tab[0][2]=NEGRO;
        tab[0][3]=NEGRO;
        tab[1][1]=NEGRO;
        tab[1][3]=NEGRO;
        tab[1][5]=NEGRO;
        tab[2][2]=NEGRO;
        tab[2][4]=NEGRO;
        tab[3][2]=NEGRO;
        tab[4][2]=NEGRO;
        
        tab[1][2]=BLANCO;
        tab[2][3]=BLANCO;
        tab[3][3]=BLANCO;
        tab[3][4]=BLANCO;
        */
        this.setValoresPosicion();
    }
    public void setValoresPosicion(){ //coloca los pesos para la matriz
        tableroPesos[0][0] = 120;
        tableroPesos[0][1] = -20;
        tableroPesos[0][2] = 20;
        tableroPesos[0][3] = 5;
        tableroPesos[1][0] = -20;
        tableroPesos[1][1] = -40;
        tableroPesos[1][2] = -5;
        tableroPesos[1][3] = -5;
        tableroPesos[2][0] = 20;
        tableroPesos[2][1] = -5;
        tableroPesos[2][2] = 15;
        tableroPesos[2][3] = 3;
        tableroPesos[3][0] = 5;
        tableroPesos[3][1] = -5;
        tableroPesos[3][2] = 3;
        tableroPesos[3][3] = 3;
        
        for(int i=0; i<4; i++){
            for(int j=0; j<4; j++){
                tableroPesos[i+4][j] = tableroPesos[3-i][j];  //subcuadro superior derecho
                tableroPesos[i][j+4] = tableroPesos[i][3-j];  //subcuadro inferior izquierdo
                tableroPesos[i+4][j+4] = tableroPesos[3-i][3-j];  //subcuadro inferior derecho                
            }
        }
        System.out.println("Matriz de pesos por posicion");
        imprimirMatriz(tableroPesos); 
        imprimirMatriz(tab); 
        
    }
    
    public void imprimirMatriz(int[][] mat){
        System.out.print("  ");
        for(int j=0; j<8; j++){
                System.out.print(" "+j+" ");
            }
           System.out.println();
        for(int j=0; j<9; j++){
                System.out.print("---");
            }
        System.out.print("\n");
        for(int i=0; i<8; i++){
            System.out.print(i+"|");            
            for(int j=0; j<8; j++){
                System.out.print(" "+mat[i][j]+" ");
            }
            System.out.print("\n");
        } 
    }
    
    public void mostrarFichas(){
        System.out.println("Fichas Blancas (Persona):: "+this.contarBlancos());
        System.out.println("Fichas Negras (Compu) ::"+this.contarNegras());
    }
    
    public void jugar(){
        while((this.finPartida()<0)&&(this.sintiros<2) ){            
            TiroComputadora(); 
            mostrarFichas();
            TiroPersona();
                       
        }
        int totalb = this.contarBlancos();
        int totaln = this.contarNegras();
        if ((this.finPartida()==1)||(totalb>totaln)){
            System.out.println("GANASTE!!!!!");            
        }else if ((this.finPartida()==2)||(totaln>totalb)){
            System.out.println("TE GANO LA COMPU xD!!!!!");
        }else{
            System.out.println("ESTO FUE UN EMPATE!!!!!");
        }
        System.out.println("Fichas Blancas: "+totalb);
        System.out.println("Fichas Negras: "+totaln);
        
    }
    
    public boolean existenTiros(int jug){
        boolean hay=false;
        for (int i=0;i<8;i++){
            for (int j=0;j<8;j++){
                if (this.validarTiro(i, j, jug)){
                    hay=true;
                    j=8;i=8;
                }
            }
        }
        return hay;
    }
    
    public void TiroPersona(){
        
        if (this.existenTiros(this.PERSONA)){
            if (this.sintiros>0){
                this.sintiros--;
            }
        System.out.println("/***Juega Persona******/");
        if(this.finPartida()<0){
            //hacer el tiro
            pedirPosicionTiro();
            this.imprimirMatriz(tab);
        }else{
            //imprimir estadisticas de final del juegos;
            
        }
        }else{
            this.sintiros++;
            System.out.println("Usted ya no tiene tiros validos");
        }
        
    }
    
    public void pedirPosicionTiro(){
        pasaTurno = false;
        boolean tirovalido=false;
        
     BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        while(!tirovalido){
        
            
            System.out.print("Ingrese Fila: ");
            String cad;
            try {
                cad = in.readLine();
                this.PosYin= Integer.valueOf(cad);
            cad=null;
            System.out.print("Ingrese Columna: ");            
            cad = in.readLine();            
            this.PosXin= Integer.valueOf(cad);   
            } catch (IOException ex) {
                Logger.getLogger(minimax.class.getName()).log(Level.SEVERE, null, ex);
            }
                     
        
        
        System.out.println("fila: "+PosYin+" columna: "+PosXin);
        tirovalido = validarTiro(PosXin,PosYin,this.PERSONA);
        if (!tirovalido){
           System.out.println("Tiro NO valido ingrese otra poscion!!!!");
        }
        }
        /***********Se tiene el tiro valido entonces se cambian las fichas en el tablero*************/
        this.flanquear_direcciones(PosXin, PosYin, this.PERSONA, true);        
    }
    
    public boolean validarTiro(int px,int py, int jug){
        boolean valido=false;
        if ( ((px>=0 )&& (px < 8)) && ((py>=0) && (py<8) ) ){
            if (tab[py][px]==0){
                if (flanquear_direcciones(px,py,jug,false)){
                    valido = true;            
                }
            }
        }
            
        return valido;
    }
    
    public boolean flanquear_direcciones(int px,int py,int jug, boolean cambiar){
    boolean flanqueo= false;
    
    if (verificar_izq_der(px,py,jug,cambiar) || verificar_der_izq(px,py,jug,cambiar) ||
        verificar_sur_norte(px,py,jug,cambiar) || verificar_norte_sur(px,py,jug,cambiar) ||
        verificar_izq_der_arriba_abajo(px,py,jug,cambiar) || verificar_der_izq_arriba_abajo(px,py,jug,cambiar) ||
            verificar_der_izq_abajo_arriba(px,py,jug,cambiar) || verificar_izq_der_abajo_arriba(px,py,jug,cambiar) 
        )
    {
        flanqueo = true;
    }
            
    return flanqueo;
    }
    
    public void TiroComputadora(){
        if (this.existenTiros(this.COMPUTADORA)){
            if (this.sintiros>0){
                this.sintiros--;
            }
        if(this.finPartida()<0){
            //hacer el tiro
            algoritmo_minimax();
        }else{
            
            //imprimir estadisticas de final del juegos;
        }
        }else{
            this.sintiros++;
            System.out.println("La computadora ya no tiene tiros");
        }
    }
    
    public void algoritmo_minimax(){
        int[][] temptab = new int[8][8];
        int nivel=0;
        int f=0;
        int c=0;
        int aux;
        int v=Integer.MIN_VALUE;
        for(int i=0;i<8;i++){
            for (int j=0;j<8;j++){
                if(this.validarTiro(i, j, this.COMPUTADORA)){
                    /** comienza algoritmo*******/
                    /***copio el tablero actual*******/
                    temptab = this.copiar_matriz(tab);
                    
                    /******** hago el tiro valido ********/
                    this.flanquear_direcciones(i, j, this.COMPUTADORA, true);
                    
                    /********obtengo el maximo************/
                    aux=min(nivel)+this.tableroPesos[i][j];
                    if (aux>v){
                        v=aux;
                        c=i;
                        f=j;
                    }
                   // System.out.println("Tiro evaluado realizado*/////////////////////");
                   // this.imprimirMatriz(tab);
                    //************ regreso a la posicion antes del tiro**********/
                    tab = this.copiar_matriz(temptab);
                    
                   // System.out.println("/****************val aux = "+aux+"******** f: "+j+" ,c: "+ i+ "***********************/ ");
                   // System.out.println("/****************val aux = "+aux+"******** f: "+f+" ,c: "+ c+ "***********************/ ");
                    /**********************************************/
                }
            }
        }
        this.flanquear_direcciones(c, f, this.COMPUTADORA, true);
        System.out.println("Tiro realizado COMPUTADORA F::"+f+" C::"+c+"*/////////////////////");
                    this.imprimirMatriz(tab);
    }
    
    public int min(int nivel){
        int [][] temptab= new int[8][8];
        if ((this.finPartida()>0)||(nivel>=this.profundidad)){
             return this.calcularHeuristica(this.PERSONA);
        }       
        
        int aux; 
        int v=Integer.MAX_VALUE;
           
              //if (nivel<profundidad){
                   for (int i=0;i<8;i++){
                     for (int j=0;j<8;j++){
                         if(this.validarTiro(i, j, this.PERSONA)){
                        /***copio el tablero actual*******/
                    temptab = this.copiar_matriz(tab);
                    
                    /******** hago el tiro valido ********/
                    this.flanquear_direcciones(i, j, this.PERSONA, true);
                    nivel++;
                    aux = max(nivel)+this.tableroPesos[i][j];
                    if (aux<v) v=aux;                                
                    /********obtengo el maximo************/
             //       aux=max(nivel);
             //       if (aux<v) v=aux;                                
                   //  System.out.println("Tiro evaluado realizado EN MIN:: *"+aux+"/////////////////////");
                   // this.imprimirMatriz(tab);
                    //************ regreso a la posicion antes del tiro**********/
                    tab = this.copiar_matriz(temptab);
                         }
            }
        }
              /*}else{
                  return 0;
              }*/
          
          return v;
    }
    
    public int max(int nivel){
        int temptab[][] = new int[8][8];
        if ((this.finPartida()>0)||(nivel>=this.profundidad)){
             return this.calcularHeuristica(this.COMPUTADORA);
        }
        int aux;
        int v=Integer.MIN_VALUE;
        for (int i=0;i<8;i++){
            for (int j=0;j<8;j++){
                if(this.validarTiro(i, j, this.COMPUTADORA)){
                 /***copio el tablero actual*******/
                    temptab = this.copiar_matriz(tab);
                    
                    /******** hago el tiro valido ********/
                    this.flanquear_direcciones(i, j, this.COMPUTADORA, true);                    
                    nivel++;
                    aux = min(nivel)+this.tableroPesos[i][j];
                    if (aux>v) v=aux;
                  //  System.out.println("Tiro evaluado realizado EN MAX:: *"+aux+"/////////////////////");
                  //  this.imprimirMatriz(tab);
                    tab = this.copiar_matriz(temptab);
                }
            }
        }
        return v;
    }
    
    public int calcularHeuristica(int jugador){
        int sum_jugador_actual=0;        
        int sum_oponente=0;
        int heuristica=0;
        for (int i=0;i<8;i++){
            for (int j=0;j<8;j++){
                if (this.tab[i][j]==jugador){
                    sum_jugador_actual+=this.tableroPesos[i][j];
                }else if(this.tab[i][j]!=0){
                    sum_oponente+=this.tableroPesos[i][j];
                }
            }
        }
       // System.out.println("ja:: "+sum_jugador_actual);
       // System.out.println("op:: "+sum_oponente);
        if (sum_oponente==0){
            sum_oponente=1;
        }
        heuristica=sum_jugador_actual/sum_oponente;        
        return heuristica;
    }
    /*
    public int conteoFinal(int ganador){
    int conteo=0;
        int contb= this.contarBlancos();
            int contn= this.contarNegras();
            switch(this.finPartida()){                
                case 1: return contb;
                case 2: return -contn;    
            }
    return conteo;
    }*/
    
    public int[][] copiar_matriz(int[][] taborigen){
        int[][] ttab = new int[8][8];
        for (int i=0;i<8;i++){
            for (int j=0;j<8;j++){
                ttab[i][j]= taborigen[i][j];
            }
        }
        return ttab;
    }
    
    public boolean verificar_norte_sur(int px, int py, int jug, boolean cambiar) {
        boolean valido =false;
        boolean breaking=false;
        int cont = 0;
        int tempx = 0;
        int tempy = 0;
        tempy = py;
        tempx = px;
        int ficha = 0;
        if (jug == 1) {
            ficha = 2;
        } else {
            ficha = 1;
        }
        if (tempy < 7) {
            tempy++;
        }
        while (tab[tempy][tempx] == ficha && !breaking) {
            cont++;
            if (tempy < 7) {
                tempy++;
            }else if (tempy == 7){
                breaking=true;
                break;
            }
        }
        if (!cambiar) {
            if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
                int[] tempCoor = new int[2];
                tempCoor[0] = py;
                tempCoor[1] = px;
                valido = true;
            }
        } else if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
            for (int i = py; i < tempy; i++) {
                tab[i][px] = jug;
            }
        }
        return valido;
    }
    
    public boolean verificar_izq_der(int px, int py, int jug, boolean cambiar) {
        boolean valido =false;
        boolean breaking = false;
        int cont = 0;
        int tempx = 0;
        int tempy = 0;
        tempy = py;
        tempx = px;
        int ficha = 0;
        if (jug == 1) {
            ficha = 2;
        } else {
            ficha = 1;
        }
        if (tempx < 7) {
            tempx++;
        }
        while (tab[tempy][tempx] == ficha && !breaking) {
            cont++;
            if (tempx < 7) {
                tempx++;
            }else if (tempx == 7){
                breaking=true;
                break;
            }
        }

        if (!cambiar) {
            if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
                int[] tempCoor = new int[2];
                tempCoor[0] = py;
                tempCoor[1] = px;
                valido =true;
            }
        } else if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
            for (int i = px; i < tempx; i++) {
                tab[py][i] = jug;
            }
        }
        return valido;
    } 
    
    public boolean verificar_der_izq(int px, int py, int jug, boolean cambiar) {
        boolean valido =false;
        boolean breaking=false;
        int cont = 0;
        int tempx = 0;
        int tempy = 0;
        tempy = py;
        tempx = px;        
        int ficha = 0;
        if (jug == 1) {
            ficha = 2;
        } else {
            ficha = 1;
        }
        if (tempx > 0) {
            tempx--;
        }
        while (tab[tempy][tempx] == ficha && !breaking) {
            cont++;
            if (tempx > 0) {
                tempx--;
            }else if (tempx == 0){
                breaking=true;
                break;
            }
        }

        if (!cambiar) {
            if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
                int[] tempCoor = new int[2];
                tempCoor[0] = py;
                tempCoor[1] = px;
                valido = true;
            }
        } else if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
            for (int i = px; i > tempx; i--) {
                tab[py][i] = jug;
            }
        }
        return valido;
    }
    
    public boolean verificar_sur_norte(int px, int py, int jug, boolean cambiar) {
        boolean valido =false;
        boolean breaking=false;
        int cont = 0;
        int tempx = 0;
        int tempy = 0;
        tempy = py;
        tempx = px;
        int ficha = 0;
        if (jug == 1) {
            ficha = 2;
        } else {
            ficha = 1;
        }
        if (tempy > 0) {
            tempy--;
        }

        while (tab[tempy][tempx] == ficha && !breaking) {
            cont++;
            if (tempy > 0) {
                tempy--;    
            }else if (tempy == 0){
                breaking=true;
                break;
            }
        }

        if (!cambiar) {
            if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
                int[] tempCoor = new int[2];
                tempCoor[0] = py;
                tempCoor[1] = px;
                valido= true;
            }
        } else if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
            for (int i = py; i > tempy; i--) {
                tab[i][px] = jug;
            }
        }
        return valido;
    }
    
    public boolean verificar_izq_der_arriba_abajo(int px, int py, int jug, boolean cambiar) {
        boolean valido =false;
        boolean breaking=false;
        int cont = 0;
        int tempx = 0;
        int tempy = 0;
        tempy = py;
        tempx = px;
        int ficha = 0;
        if (jug == 1) {
            ficha = 2;
        } else {
            ficha = 1;
        }
        if (tempy < 7) {
            tempy++;
        }
        if (tempx < 7) {
            tempx++;
        }
        while (tab[tempy][tempx] == ficha && !breaking) {
            cont++;
            if (tempy < 7) {
                tempy++;
            }else if (tempy == 7){
                breaking=true;
                break;
            }
            
            
            if (tempx < 7) {
                tempx++;
            }else if (tempx == 7){
                breaking=true;
                break;
            }
        }

        if (!cambiar) {
            if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
                int[] tempCoor = new int[2];
                tempCoor[0] = py;
                tempCoor[1] = px;
                valido = true;
            }
        } else if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
            int j = px;
            for (int i = py; i < tempy; i++) {
                tab[i][j] = jug;
                j++;
            }
        }
        return valido;
    }
    
    public boolean verificar_der_izq_arriba_abajo(int px, int py, int jug, boolean cambiar) {
        boolean valido =false;
        boolean breaking=false;
        int cont = 0;
        int tempx = 0;
        int tempy = 0;
        tempy = py;
        tempx = px;
        int ficha = 0;
        if (jug == 1) {
            ficha = 2;
        } else {
            ficha = 1;
        }
        if (tempy < 7) {
            tempy++;
        }
        if (tempx > 0) {
            tempx--;
        }
        while (tab[tempy][tempx] == ficha && !breaking) {
            cont++;
            if (tempy < 7) {
                tempy++;
            }else if (tempy == 7){
                breaking =true;
                break;
            }
            
            
            if (tempx > 0) {
                tempx--;
            }else if (tempx == 0){
                breaking =true;
                break;
            }
        }

        if (!cambiar) {
            if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
                int[] tempCoor = new int[2];
                tempCoor[0] = py;
                tempCoor[1] = px;
                valido = true;
            }
        } else if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
            int j = px;
            for (int i = py; i < tempy; i++) {
                tab[i][j] = jug;
                j--;
            }
        }
        return valido;
    }
    
    public boolean verificar_der_izq_abajo_arriba(int px, int py, int jug, boolean cambiar) {
        boolean valido =false;
        boolean breaking=false;
        int cont = 0;
        int tempx = 0;
        int tempy = 0;
        tempy = py;
        tempx = px;
        int ficha = 0;
        if (jug == 1) {
            ficha = 2;
        } else {
            ficha = 1;
        }
        if (tempy > 0) {
            tempy--;
        }
        if (tempx > 0) {
            tempx--;
        }
        while (tab[tempy][tempx] == ficha && !breaking) {
            cont++;
            if (tempy > 0) {
                tempy--;
            }else if (tempy == 0){
                breaking=true;
                break;
            }
            if (tempx > 0) {
                tempx--;
            }else if (tempx == 0){
                breaking=true;
                break;
            }
        }

        if (!cambiar) {
            if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
                int[] tempCoor = new int[2];
                tempCoor[0] = py;
                tempCoor[1] = px;
                valido = true;
            }
        } else if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
            int j = px;
            for (int i = py; i > tempy; i--) {
                tab[i][j] = jug;
                j--;
            }
        }
        return valido;
    }
    
    public boolean verificar_izq_der_abajo_arriba(int px, int py, int jug, boolean cambiar) {
        boolean valido =false;
        boolean breaking = false;
        int cont = 0;
        int tempx = 0;
        int tempy = 0;
        tempy = py;
        tempx = px;
        int ficha = 0;
        if (jug == 1) {
            ficha = 2;
        } else {
            ficha = 1;
        }
        
        if (tempy > 0) {
            tempy--;
        }
        if (tempx < 7) {
            tempx++;
        }
        while (tab[tempy][tempx] == ficha && !breaking) {
            cont++;
            if (tempy > 0) {
                tempy--;
            }else if (tempy == 0){
                breaking =true;
                break;
            }
            
            if (tempx < 7) {
                tempx++;
            }else if (tempx == 7){               
                breaking =true;
                break;
            }
        }

        if (!cambiar) {
            if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
                int[] tempCoor = new int[2];
                tempCoor[0] = py;
                tempCoor[1] = px;
                valido = true;
            }
        } else if (tab[tempy][tempx] == jug && cont > 0 && !breaking) {
            int j = px;
            for (int i = py; i > tempy; i--) {
                tab[i][j] = jug;
                j++;
            }
        }
        return valido;
    }
    
    
    public int contarVacios(){
        int vacios=0;
        for(int i=0;i<8;i++){
            for(int j=0;j<8;j++){
                if(tab[i][j] == 0){
                    vacios++;
                }
            }
        }
        return vacios;
    }
    
    public int contarBlancos(){
        int blancos=0;
        for(int i=0;i<8;i++){
            for(int j=0;j<8;j++){
                if(tab[i][j] == 1){
                    blancos++;
                }
            }
        }
        return blancos;
    }
    
    public int contarNegras(){
        int negras=0;
        for(int i=0;i<8;i++){
            for(int j=0;j<8;j++){
                if(tab[i][j] == 2){
                    negras++;
                }
            }
        }
        return negras;
    }
    
    public int finPartida(){
        int fin=-1;
        
        if (this.contarBlancos() == 0){
            //**** se acabo el juego
            fin = 0;
            
        }else if (this.contarNegras()==0){
            /**********  gano blancas =  1************/
            fin = 1;
            
        }else if (this.contarBlancos()==0){
            /************** gano negras = 2**************/
            fin = 2;
            
        }
        return fin;        
    }
    
}
